home *** CD-ROM | disk | FTP | other *** search
- /*
- File: FDPUtilities.c
-
- Description: utilities used in FinderDragPro.c. Routines in this file are used in the
- FinderDragPro.c file; however, since they are not directly related
- to the example, they have been moved here to simplify the main file.
-
- Author: John Montbriand
-
- Copyright: Copyright: © 1999 by Apple Computer, Inc.
- all rights reserved.
-
- Disclaimer: You may incorporate this sample code into your applications without
- restriction, though the sample code has been provided "AS IS" and the
- responsibility for its operation is 100% yours. However, what you are
- not permitted to do is to redistribute the source as "DSC Sample Code"
- after having made changes. If you're going to re-distribute the source,
- we require that you make it clear in the source that the code was
- descended from Apple Sample Code, but that you've made changes.
-
- Change History (most recent first):
- 9/9/99 created by John Montbriand
- */
-
- #include "FDPUtilities.h"
- #include <QuickDraw.h>
- #include <Gestalt.h>
- #include <Palettes.h>
- #include <Threads.h>
- #include <fp.h>
-
-
-
- /* ValidFSSpec verifies that *spec refers is formatted correctly, and it
- verifies that it refers to an existing file in an existing directory on
- and existing volume. If *spec is valid, the function returns noErr,
- otherwise an error is returned. */
- OSErr ValidFSSpec(FSSpec *spec) {
- FInfo fndrInfo;
- /* check the name's size */
- if (spec->name[0] + (sizeof(FSSpec) - sizeof(spec->name)) > sizeof(FSSpec)) return paramErr;
- /* ckeck if it refers to a file */
- return FSpGetFInfo(spec, &fndrInfo);
- }
-
-
- /* ResolveAliasQuietly resolves an alias using a fast search with no user interaction. Our main loop
- periodically resolves gFileAlias comparing the result to gTargetFile to keep the display up to date.
- As a result, we would like the resolve alias call to be as quick as possible AND since the application
- may be in the background when it is called, we don't want any user interaction. */
- OSErr ResolveAliasQuietly(ConstFSSpecPtr fromFile, AliasHandle alias, FSSpec *target, Boolean *wasChanged) {
- short aliasCount;
- Boolean needsUpdate;
- OSErr err;
- /* set up locals */
- aliasCount = 1;
- needsUpdate = false;
- *wasChanged = false;
- /* call MatchAlias to resolve the alias.
- kARMNoUI = no user interaction,
- kARMSearch = do a fast search. */
- err = MatchAlias(NULL, (kARMNoUI | kARMSearch), alias, &aliasCount, target, &needsUpdate, NULL, NULL);
- if (err == noErr) {
- /* if the alias was changed, update it. */
- err = UpdateAlias(fromFile, target, alias, wasChanged);
- }
- return err;
- }
-
-
-
- /* MakeHFSFlavorFromAlias converts an alias handle into a HFSFlavor
- structure filling in the fields with their correct values. */
- OSErr MakeHFSFlavorFromAlias(AliasHandle theAlias, HFSFlavor *theFlavor) {
- OSErr err = noErr;
- Boolean wasChanged;
- CInfoPBRec cat;
-
- /* resolve the alias with no user interaction. Do a fast search. */
- err = ResolveAliasQuietly(NULL, theAlias, &theFlavor->fileSpec, &wasChanged);
- if (err != noErr) return err;
-
- /* pull some information about the file */
- cat.hFileInfo.ioNamePtr = theFlavor->fileSpec.name;
- cat.hFileInfo.ioVRefNum = theFlavor->fileSpec.vRefNum;
- cat.hFileInfo.ioDirID = theFlavor->fileSpec.parID;
- cat.hFileInfo.ioFDirIndex = 0;
- err = PBGetCatInfoSync(&cat);
- if (err != noErr) return err;
-
- /* save the finder flags */
- theFlavor->fdFlags = cat.hFileInfo.ioFlFndrInfo.fdFlags;
-
- /* calculate the type and creator */
- if (theFlavor->fileSpec.parID == fsRtParID) {
- /* volumes have parrent id == 1 */
- theFlavor->fileCreator = 'MACS';
- theFlavor->fileType = 'disk';
- } else if ((cat.hFileInfo.ioFlAttrib & ioDirMask) != 0) {
- /* directories have bit 4 set in the attributes */
- theFlavor->fileCreator = 'MACS';
- theFlavor->fileType = 'fold';
- } else {
- /* assume anything else is a file */
- theFlavor->fileCreator = cat.hFileInfo.ioFlFndrInfo.fdCreator;
- theFlavor->fileType = cat.hFileInfo.ioFlFndrInfo.fdType;
- }
-
- /* done */
- return noErr;
- }
-
-
-
-
-
- /* IconsToMaskedPixMap converts either an IconServices icon reference or a IconUtilities icon suite into a
- (GWorldPtr, RgnHandle) pair appropriate for dragging as a transparent icon image. if iconReference
- then calls to IconServices are made, if iconSuite is not null, then calls to icon services are made.
- The resulting graphics world and region handle are returned in *imageGWorld and *maskRgn. */
- OSErr IconsToMaskedPixMap(const Rect *iconRect, Handle iconSuite, IconRef iconReference,
- GWorldPtr *imageGWorld, RgnHandle *maskRgn) {
- OSErr err;
- GWorldPtr theWorld;
- RgnHandle theMask;
- Rect imageRect;
- Point offsetPt;
- GDHandle saveDevice;
- CGrafPtr savePort;
- PixMapHandle imagePixMap;
-
- /* set up locals */
- theWorld = NULL;
- theMask = NULL;
- imageRect = *iconRect;
- OffsetRect(&imageRect, -imageRect.left, -imageRect.top);
- LocalToGlobal(&offsetPt);
-
- /* create the graphics world */
- err = NewGWorld(&theWorld, 8, &imageRect, NULL, NULL, 0);
- if (err != noErr) goto bail;
- if (theWorld == NULL) { err = memFullErr; goto bail; } /* often missed... */
-
- /* set up the mask region */
- theMask = NewRgn();
- if (theMask == NULL) { err = memFullErr; goto bail; }
-
- /* calculate the icon's mask region */
- if (iconReference != NULL)
- err = IconRefToRgn(theMask, &imageRect, kAlignNone, kIconServicesNormalUsageFlag, iconReference);
- else if (iconSuite != NULL)
- err = IconSuiteToRgn(theMask, &imageRect, kAlignNone, iconSuite);
- else err = paramErr;
- if (err != noErr) goto bail;
-
- /* set up the drawing environment */
- GetGWorld (&savePort, &saveDevice);
- LockPixels((imagePixMap = GetGWorldPixMap(theWorld)));
- SetGWorld(theWorld, NULL);
-
- /* draw the icon suite */
- EraseRect(&imageRect);
- if (iconReference != NULL)
- err = PlotIconRef(&imageRect, kAlignNone, kTransformNone, kIconServicesNormalUsageFlag, iconReference);
- else err = PlotIconSuite(&imageRect, kAlignNone, kTransformNone, iconSuite);
-
- /* restore the drawing environment */
- SetGWorld(savePort, saveDevice);
- UnlockPixels(imagePixMap);
-
- /* after restoring, check drawing result */
- if (err != noErr) goto bail;
-
- /* store what we created. */
- *imageGWorld = theWorld;
- *maskRgn = theMask;
- return noErr;
- bail:
- if (theWorld != NULL) DisposeGWorld(theWorld);
- if (theMask != NULL) DisposeRgn(theMask);
- return err;
- }
-
-
- /* GrayOutBox grays out an area of the screen in the current grafport.
- *theBox is in local coordinates in the current grafport. This routine
- is for direct screen drawing only. */
- void GrayOutBox(Rect *theBox) {
- long response;
- Rect globalBox;
- GDHandle maxDevice;
- RGBColor rgbWhite = {0xFFFF, 0xFFFF, 0xFFFF}, rgbBlack = {0, 0, 0}, sForground, sBackground;
- PenState penSave;
- /* save the current drawing state */
- GetPenState(&penSave);
- /* if no color quickdraw, fail...*/
- if (Gestalt(gestaltQuickdrawVersion, &response) != noErr) response = 0;
- if (response >= gestalt8BitQD) {
- /* get the device for the rectangle */
- globalBox = *theBox;
- LocalToGlobal((Point*) &globalBox.top);
- LocalToGlobal((Point*) &globalBox.bottom);
- maxDevice = GetMaxDevice(&globalBox);
- if (maxDevice != NULL) {
- /* calculate the best gray */
- if ( GetGray(maxDevice, &rgbWhite, &rgbBlack)) {
- /* draw over the area in gray using addMax transfer mode */
- GetForeColor(&sForground);
- GetBackColor(&sBackground);
- RGBForeColor(&rgbBlack);
- RGBBackColor(&rgbWhite);
- PenMode(addMax);
- PaintRect(theBox);
- RGBForeColor(&sForground);
- RGBBackColor(&sBackground);
- /* restore the pen state and leave */
- SetPenState(&penSave);
- return;
- }
- }
- }
- /* fall through to using the gray pattern */
- PenPat(&qd.gray);
- PenMode(notPatBic);
- PaintRect(theBox);
- SetPenState(&penSave);
- }
-
-
- /* ShowDragHiliteBox is called to hilite the drop box area in the
- main window. Here, we draw a 3 pixel wide border around *boxBounds. */
- OSErr ShowDragHiliteBox(DragReference theDragRef, Rect *boxBounds) {
- RgnHandle boxRegion, insetRegion;
- OSErr err;
- Rect box;
- /* set up locals */
- boxRegion = insetRegion = NULL;
- /* create the region */
- if ((boxRegion = NewRgn()) == NULL) { err = memFullErr; goto bail; }
- if ((insetRegion = NewRgn()) == NULL) { err = memFullErr; goto bail; }
- box = *boxBounds;
- InsetRect(&box, -5, -5);
- RectRgn(boxRegion, &box);
- InsetRect(&box, 3, 3);
- RectRgn(insetRegion, &box);
- DiffRgn(boxRegion, insetRegion, boxRegion);
- /* hilite the region */
- err = ShowDragHilite(theDragRef, boxRegion, true);
- bail:
- /* clean up and leave */
- if (boxRegion != NULL) DisposeRgn(boxRegion);
- if (insetRegion != NULL) DisposeRgn(insetRegion);
- return err;
- }
-
-
-
-
-
- /* CopyCommandParam includes the parameters used for a copy
- operation. A record of this type is created in the CopyFileCmd routine,
- and a pointer to it is passed to a Thread Manager task that does
- the actual copy. */
- typedef struct {
- FSSpec src, dst;
- short srcRef, dstRef;
- unsigned long total, number;
- CopyCallback callback;
- CopyErrorHandler errorhandler;
- ThreadID copythread;
- Ptr copyBuffer;
- } CopyCommandParam, *CopyCmdParamPtr;
-
-
- CopyCmdParamPtr gCopyParam = NULL;
-
- /* CopyFileInProgress returns true if a copy command is in
- progress. In this implementation, it simply checks to see
- if gCopyParam is not NULL. */
- Boolean CopyFileInProgress(void) {
- return (gCopyParam != NULL);
- }
-
- /* AbortCopyOperation aborts an ongoing copy operation. this routine
- deallocates any structures allocated and deletes the target file. It
- also tears down the thread. */
- void AbortCopyOperation(void) {
- if (gCopyParam != NULL) {
- gCopyParam->errorhandler(&gCopyParam->src, userCanceledErr);
- gCopyParam->callback(&gCopyParam->src, kCopyEnd, 100);
- DisposeThread(gCopyParam->copythread, 0, false);
- if (gCopyParam->copyBuffer != NULL)
- DisposePtr((Ptr) gCopyParam->copyBuffer);
- if (gCopyParam->srcRef != 0) FSClose(gCopyParam->srcRef);
- if (gCopyParam->dstRef != 0) FSClose(gCopyParam->dstRef);
- FSpDelete(&gCopyParam->dst);
- DisposePtr((Ptr) gCopyParam);
- gCopyParam = NULL;
- }
- }
-
-
- /* CopyForkOperation copies forkLength bytes from the source file to the destination
- file using (buffer, bufferSize) as a data buffer during the copy. As the copy proceeds,
- the value of gBytesCopied is updated to indicate the total number of bytes copied. */
- static OSErr CopyForkOperation(CopyCmdParamPtr param, long forkLength) {
- long bytecount, count, percent;
- OSErr err;
-
- bytecount = 0;
- while (bytecount < forkLength) {
- count = forkLength - bytecount;
- if (count > kCopyBufferSize) count = kCopyBufferSize;
-
- err = FSRead(param->srcRef, &count, param->copyBuffer);
- if (err != noErr) return err;
- YieldToAnyThread();
-
- err = FSWrite(param->dstRef, &count, param->copyBuffer);
- if (err != noErr) return err;
- YieldToAnyThread();
-
- bytecount += count;
- param->number += count;
- if (param->total == 0)
- percent = 100;
- else percent = rinttol((((float) param->number) / ((float) param->total)) * 100.0);
- param->callback(¶m->src, kCopyRun, percent);
- YieldToAnyThread();
-
- }
- return noErr;
- }
-
- /* CopyCommandThread is a Thread Manager task that completes a copy operation.
- The task is started in the CopyFileCmd routine. */
- static pascal void* CopyCommandThread(void *threadParam) {
- CopyCmdParamPtr param;
- CInfoPBRec cat;
- OSErr err;
- /* set up */
- param = (CopyCmdParamPtr) threadParam;
- YieldToAnyThread();
- /* calculate the total bytes */
- cat.hFileInfo.ioNamePtr = param->src.name;
- cat.hFileInfo.ioVRefNum = param->src.vRefNum;
- cat.hFileInfo.ioDirID = param->src.parID;
- cat.hFileInfo.ioFDirIndex = 0;
- err = PBGetCatInfoSync(&cat);
- if (err != noErr) goto bail;
- if ((cat.hFileInfo.ioFlAttrib & ioDirMask) != 0) {
- err = kCannotCopyDirError;
- goto bail;
- }
- param->total = cat.hFileInfo.ioFlLgLen + cat.hFileInfo.ioFlRLgLen;
-
- /* file created, switch out */
- YieldToAnyThread();
-
- /* allocate the copy buffer */
- param->copyBuffer = NewPtr(kCopyBufferSize);
- if (param->copyBuffer == NULL) { err = memFullErr; goto bail; }
-
- /* copy the data fork, if there is one */
- if (cat.hFileInfo.ioFlLgLen > 0) {
- err = FSpOpenDF(¶m->src, fsRdPerm, ¶m->srcRef);
- if (err != noErr) goto bail;
- err = FSpOpenDF(¶m->dst, fsWrPerm, ¶m->dstRef);
- if (err != noErr) goto bail;
- err = CopyForkOperation(param, cat.hFileInfo.ioFlLgLen);
- if (err != noErr) goto bail;
- FSClose(param->srcRef);
- param->srcRef = 0;
- FSClose(param->dstRef);
- param->dstRef = 0;
- }
- /* copy the resource fork, if there is one */
- if (cat.hFileInfo.ioFlRLgLen > 0) {
- err = FSpOpenRF(¶m->src, fsRdPerm, ¶m->srcRef);
- if (err != noErr) goto bail;
- err = FSpOpenRF(¶m->dst, fsWrPerm, ¶m->dstRef);
- if (err != noErr) goto bail;
- err = CopyForkOperation(param, cat.hFileInfo.ioFlRLgLen);
- if (err != noErr) goto bail;
- FSClose(param->srcRef);
- param->srcRef = 0;
- FSClose(param->dstRef);
- param->dstRef = 0;
- }
- /* flush the destination volume */
- FlushVol(NULL, param->dst.vRefNum); /* err = best effort */
- /* clean up */
- param->callback(¶m->src, kCopyEnd, 100);
- DisposePtr(param->copyBuffer);
- param->copyBuffer = NULL;
- DisposePtr((Ptr) param);
- gCopyParam = NULL;
- return NULL;
- bail:
- param->errorhandler(¶m->src, err);
- param->callback(¶m->src, kCopyEnd, 100);
- if (param->srcRef != 0) FSClose(param->srcRef);
- if (param->dstRef != 0) FSClose(param->dstRef);
- if (param->copyBuffer != NULL) DisposePtr(param->copyBuffer);
- FSpDelete(¶m->dst);
- DisposePtr((Ptr) param);
- gCopyParam = NULL;
- return NULL;
- }
-
- OSErr CopyFileCmd(FSSpec *theSource, FSSpec *theTarget, CopyCallback callback, CopyErrorHandler errorhandler) {
- CopyCmdParamPtr param;
- OSErr err;
- Boolean threadCreated;
- /* set up locals */
- threadCreated = true;
- param = NULL;
- /* check copy conditions */
- if (gCopyParam != NULL) return kCopyNotRentrantError;
- /* set up param */
- param = (CopyCmdParamPtr) NewPtr(sizeof(CopyCommandParam));
- if (param == NULL) { err = memFullErr; goto bail; }
- param->src = *theSource;
- param->dst = *theTarget;
- param->srcRef = 0;
- param->dstRef = 0;
- param->total = param->number = 0;
- param->callback = callback;
- param->errorhandler = errorhandler;
- param->copyBuffer = NULL;
- /* create a thread */
- err = NewThread(kCooperativeThread, CopyCommandThread, param, 0, kCreateIfNeeded, NULL, ¶m->copythread);
- if (err != noErr) goto bail;
- threadCreated = true;
- gCopyParam = param;
- callback(¶m->src, kCopyStart, 0);
- return noErr;
- bail:
- if (threadCreated)
- DisposeThread(param->copythread, 0, false);
- if (param != NULL) DisposePtr((Ptr) param);
- return err;
- }
-
-
-
-